package core.agent;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;

import core.api.DFservice;
import core.api.DbData;
import core.api.DbManager;
import core.api.EventNormalization;
import core.datamodel.AccountData;
import core.datamodel.Constants;
import core.datamodel.Element;
import core.datamodel.ResourceCounter;
import core.datamodel.ElementValue;
import core.datamodel.Event;
import core.datamodel.Property;
import core.datamodel.Resource;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.util.Logger;

public class AgentInventory extends Agent {

	private Logger log = Logger.getJADELogger(this.getClass().getName());
	private DbManager db;
	private Connection conDb;
	private DbData dbData;
	private DFservice DFsrv = new DFservice();

	protected void setup() {

		// Register the calculator service in the yellow pages
		DFsrv.registerAgent("manager-inventory", this);


		log.info("Apro Connessione al DB");
		db = new DbManager();
		conDb = db.open();
		dbData = new DbData(conDb);


		// Add the behaviour serving queries from controller agent
		addBehaviour(new RequestEventServer());
	}

	// Put agent clean-up operations here
	protected void takeDown() {
		// Deregister from the yellow pages
		try {
			DFService.deregister(this);
			db.close();
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

	}

	private class RequestEventServer extends CyclicBehaviour {
		private Event event = null;
		private String action = null;
		private Resource resource = null;
		private String messageType = null;

		public void action() {

			MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.REQUEST);
			ACLMessage msg = myAgent.receive(mt);


			if (msg != null && "EVENT".equals(msg.getUserDefinedParameter("TYPE"))) {

				// Recupero i dati delle richiesta

				try {
					event = (Event) msg.getContentObject();
				
				} catch (UnreadableException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}

				action = event.getAction();

				// TODO Devo controllare e completare i dati della risora
				// se e' una delete devo aggiungere i dati resource id
				// se e' una CHANGE devo gestire i nuovi dati
				// se e' una NEW devo completare con le cose nuove ad esempio performance descriptor

				EventNormalization norm = new EventNormalization(dbData);
				try {
					event = norm.normalize(event);
				} catch (SQLException e2) {
					// TODO Auto-generated catch block
					e2.printStackTrace();
				}
				resource = event.getEventResource();


				log.info("Ricevuto un evento ... action="+event.getAction());

				try {
					if (Constants.EVENT_ACTION_NEW.equals(action)){
						// gestisco l'inserimento di un dato nella tabella customer resource
						// transazione
						log.info("Ricevuta richiesta di inserimento resource ...");

						conDb.setAutoCommit(false);

						// inserisco la nuova risorsa
						long rscId = dbData.insertResource(resource);
						event.getEventResource().setId(rscId);

						//inserisco l'evento che memorizza il cambiamento
						long evtId = dbData.insertEvent(event);

						conDb.commit();



					}else if (Constants.EVENT_ACTION_DELETE.equals(action)){
						log.info("Richiesta cancellazione risorsa con id="+resource.getId());
						// management resource delete
						conDb.setAutoCommit(false);

						// aggiornare lo status a deleted della risorsa;
						Hashtable <String,String> keyValues = new Hashtable <String,String>();
						keyValues.put("resource_status", Constants.RESOURCE_STATUS_DELETE);
						dbData.update("CUSTOMERS_RESOURCE", keyValues, resource.getId());



						log.info("Update Resource");
						long evtId = dbData.insertEvent(event);
						conDb.commit();




					}else if (Constants.EVENT_ACTION_CHANGE.equals(action)){
						// management chnge resource
						
						log.info("Recived Change event");
						conDb.setAutoCommit(false);
						
						// update change data
						ArrayList<Property> props = event.getProperties();
						resource = event.getEventResource();
						
						for ( Property pro : props){
							if (pro.getType().equals("RESOURCE")){
								if (pro.getName().equals("OFFER")) {
									
									// update offer field
									Hashtable <String,String> keyValues = new Hashtable <String,String>();
									keyValues.put("RESOURCE_OFFER", resource.getOffer());
									dbData.update("CUSTOMERS_RESOURCE", keyValues, resource.getId());
								
								}
							} else  if (pro.getType().equals("ELEMENT")){
								// update element value
								for (Element ele : resource.getElements()){
									if (ele.getName().equals(pro.getName())){
										// update element 
										Hashtable <String,String> keyValues = new Hashtable <String,String>();
										keyValues.put("ELEMENT_VALUE", ele.getValue());
										dbData.update("RESOURCE_ELEMENTS", keyValues, ele.getId());
										break;
									}
								}// for ele
									
							} // end if element
			
						} // end for prop
					
						//insert event
						dbData.insertEvent(event);
						conDb.commit();
				
					}
				} catch (SQLException e) {
					try {
						conDb.rollback();
					} catch (SQLException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					e.printStackTrace();
				}
			}
			else if ( msg!=null && "ACCOUNT".equals(msg.getUserDefinedParameter("TYPE") )) {
				// dati di account l'inserimento

				AccountData account = null;

				try {
					account = (AccountData) msg.getContentObject();
					if (account != null){
						// insert new data
						conDb.setAutoCommit(false);
						dbData.insertElementValue(account.getElementValues());
						dbData.updateAndInsertCounters(account.getCounters());
						conDb.commit();
					}

				} catch (UnreadableException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();

				} catch (SQLException e) {

					try {
						conDb.rollback();
					} catch (SQLException e1) {
						e1.printStackTrace();
					}
					e.printStackTrace();
				}


			} else if ( msg!=null && "UPDATE_RESOURCE_ELEMENT".equals(msg.getUserDefinedParameter("TYPE") )) {

				// update resource_element

				Element element=null;
				try {
					element = (Element) msg.getContentObject();
					log.info("Ricevuto msg di update di element con id="+element.getId());

					// update field external_id
					Hashtable <String,String> keyValues = new Hashtable <String,String>();
					keyValues.put("ELEMENT_EXTERNAL_ID", new Long(element.getExternalId()).toString()  );

					dbData.update("RESOURCE_ELEMENTS", keyValues, element.getId());
					conDb.commit();

				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();

				} catch (UnreadableException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			else {
				block();
			}


		}
	}  // End of inner class OfferRequestsServer



}
